#include <linux/mallocator.h>
#include <linux/hlist.h>
#include <linux/stdlib.h>
#include <linux/string.h>

static HLIST_HEAD(mallocators);

void mallocator_register(struct mallocator *m)
{
    INIT_HLIST_NODE(&m->node);
    hlist_add_head(&m->node, &mallocators);
}

void *kmalloc(unsigned long size, gfp_t flags)
{
    void *ptr = NULL;
    struct mallocator *m;

    hlist_for_each_entry(m, &mallocators, node)
    {
        if (m->size - m->used >= size)
        {
            ptr = m->alloc(m, size, flags, -1);
            break;
        }
    }

    if (flags & __GFP_ZERO && ptr)
    {
        memset(ptr, 0, size);
    }

    return ptr;
}

void kfree(const void *object)
{
    struct mallocator *m;

    hlist_for_each_entry(m, &mallocators, node)
    {
        if (object >= m->start && object < (m->start + m->size))
        {
            m->free(m, object);
            break;
        }
    }
}

void *kmalloc_node(size_t size, gfp_t flags, int node)
{
    void *ptr = NULL;
    struct mallocator *m;

    hlist_for_each_entry(m, &mallocators, node)
    {
        if (m->size - m->used >= size)
        {
            ptr = m->alloc(m, size, flags, node);
            break;
        }
    }

    if (flags & __GFP_ZERO && ptr)
    {
        memset(ptr, 0, size);
    }

    return ptr;
}
